package com.chongchong.flow.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chongchong.common.constant.ErrorCodeEnum;
import com.chongchong.core.mp.annotation.DisableDataFilter;
import com.chongchong.core.mp.object.MyPageParam;
import com.chongchong.core.secure.utils.SecureUtil;
import com.chongchong.core.tool.api.R;
import com.chongchong.flow.constant.FlowConstant;
import com.chongchong.flow.constant.FlowTaskStatus;
import com.chongchong.flow.entity.*;
import com.chongchong.flow.service.*;
import com.chongchong.flow.util.FlowOperationHelper;
import com.chongchong.flow.vo.FlowTaskCommentVo;
import com.chongchong.flow.vo.FlowTaskVo;
import com.chongchong.flow.vo.TaskInfoVo;
import com.chongchong.flow.wrapper.FlowOperationWrapper;
import com.chongchong.online.entity.OnlineForm;
import com.chongchong.online.service.IOnlineFormService;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;

import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 流程操作接口类
 *
 * @author Jerry
 * @date 2021-06-06
 */
@Api(tags = "通用流程操作接口")
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/flowOperation")
@ApiSupport(order = 3)
public class FlowOperationController {
//	@Autowired
//    private IFlowEntryService flowEntryService;
	@Autowired
    private IFlowTaskCommentService flowTaskCommentService;
	@Autowired
    private IFlowTaskExtService flowTaskExtService;
	@Autowired
    private IFlowApiService flowApiService;
	@Autowired
    private IFlowWorkOrderService flowWorkOrderService;
	@Autowired
    private IFlowMessageService flowMessageService;
	@Autowired
    private FlowOperationHelper flowOperationHelper;

	@Autowired
	private IOnlineFormService onlineFormService;

    /**
     * 根据指定流程的主版本，发起一个流程实例。
     *
     * @param processDefinitionKey 流程标识。
     * @return 应答结果对象。
     */
    @PostMapping("/startOnly")
	@ApiOperation(notes = "根据指定流程的主版本，发起一个流程实例",value = "根据指定流程的主版本，发起一个流程实例")
    public R<Void> startOnly(@RequestParam(required = true) String processDefinitionKey) throws XMLStreamException {
        // 1. 验证流程数据的合法性。
        R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
        if (!flowEntryResult.isSuccess()) {
            return R.fail(flowEntryResult.getMsg());
        }
        // 2. 验证流程一个用户任务的合法性。
        FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
        R<TaskInfoVo> taskInfoResult =
                flowOperationHelper.verifyAndGetInitialTaskInfoXml(flowEntryResult.getData().getBpmnXml(),flowEntryPublish, false);
        if (!taskInfoResult.isSuccess()) {
            return R.fail(taskInfoResult.getMsg());
        }
        flowApiService.start(flowEntryPublish.getProcessDefinitionId(), null);
        return R.success("流程实例启动成功");
    }

    /**
     * 获取开始节点之后的第一个任务节点的数据。
     *
     * @param processDefinitionKey 流程标识。
     * @return 任务节点的自定义对象数据。
     */
    @GetMapping("/viewInitialTaskInfo")
	@ApiOperation(notes = "获取开始节点之后的第一个任务节点的数据",value = "获取开始节点之后的第一个任务节点的数据")
	public R<TaskInfoVo> viewInitialTaskInfo(@RequestParam String processDefinitionKey) {
        R<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
        if (!flowEntryResult.isSuccess()) {
            return R.fail(flowEntryResult.getMsg());
        }
        FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
        String initTaskInfo = flowEntryPublish.getInitTaskInfo();
        TaskInfoVo taskInfo = StrUtil.isBlank(initTaskInfo)
                ? null : JSON.parseObject(initTaskInfo, TaskInfoVo.class);
        if (taskInfo != null) {
            taskInfo.setAssignedMe(StrUtil.equalsAny(
                    taskInfo.getAssignee(), SecureUtil.getUserAccount(), FlowConstant.START_USER_NAME_VAR));

			// 用formid获取表单呈现方式
			if(null != taskInfo.getFormId()) {
				OnlineForm onlineForm = onlineFormService.getById(taskInfo.getFormId());
				taskInfo.setPresentMode(onlineForm.getPresentMode());
			}
        }

        return R.data(taskInfo);
    }

    /**
     * 获取流程运行时指定任务的信息。
     *
     * @param processDefinitionId 流程引擎的定义Id。
     * @param processInstanceId   流程引擎的实例Id。
     * @param taskId              流程引擎的任务Id。
     * @return 任务节点的自定义对象数据。
     */
    @GetMapping("/viewRuntimeTaskInfo")
	@ApiOperation(notes = "获取流程运行时指定任务的信息",value = "获取流程运行时指定任务的信息")
	public R<TaskInfoVo> viewRuntimeTaskInfo(
            @RequestParam String processDefinitionId,
            @RequestParam String processInstanceId,
            @RequestParam String taskId) {
        Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
        R<TaskInfoVo> taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task);
        if (!taskInfoResult.isSuccess()) {
            return R.fail(taskInfoResult.getMsg());
        }
        TaskInfoVo taskInfoVo = taskInfoResult.getData();
		// 用formid获取表单呈现方式
		if(taskInfoVo != null && null != taskInfoVo.getFormId()) {
			OnlineForm onlineForm = onlineFormService.getById(taskInfoVo.getFormId());
			taskInfoVo.setPresentMode(onlineForm.getPresentMode());
		}

        FlowTaskExt flowTaskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInfoVo.getTaskKey());
        if (flowTaskExt != null) {
            if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) {
                taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class));
            }
            if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) {
                taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class));
            }
        }
        return R.data(taskInfoVo);
    }

    /**
     * 获取流程运行时指定任务的信息。
     *
     * @param processDefinitionId 流程引擎的定义Id。
     * @param processInstanceId   流程引擎的实例Id。
     * @param taskId              流程引擎的任务Id。
     * @return 任务节点的自定义对象数据。
     */
    @GetMapping("/viewHistoricTaskInfo")
	@ApiOperation(notes = "获取历史流程指定任务的信息",value = "获取历史流程指定任务的信息")
	public R<TaskInfoVo> viewHistoricTaskInfo(
            @RequestParam String processDefinitionId,
            @RequestParam String processInstanceId,
            @RequestParam String taskId) {
//        String errorMessage;
        HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
//        if (!StrUtil.equals(taskInstance.getAssignee(), SecureUtil.getUserAccount())) {
//            errorMessage = "数据验证失败，当前用户不是指派人！";
//            return R.fail(errorMessage);
//        }
        TaskInfoVo taskInfoVo = JSON.parseObject(taskInstance.getFormKey(), TaskInfoVo.class);
		// 用formid获取表单呈现方式
		if(taskInfoVo != null && null != taskInfoVo.getFormId()) {
			OnlineForm onlineForm = onlineFormService.getById(taskInfoVo.getFormId());
			taskInfoVo.setPresentMode(onlineForm.getPresentMode());
		}

        FlowTaskExt flowTaskExt =
                flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInstance.getTaskDefinitionKey());
        if (flowTaskExt != null) {
            if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) {
                taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class));
            }
            if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) {
                taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class));
            }
        }
        return R.data(taskInfoVo);
    }

    /**
     * 获取第一个提交表单数据的任务信息。
     *
     * @param processInstanceId 流程实例Id。
     * @return 任务节点的自定义对象数据。
     */
    @GetMapping("/viewInitialHistoricTaskInfo")
	@ApiOperation(notes = "获取历史任务信息",value = "获取历史任务信息")
	public R<TaskInfoVo> viewInitialHistoricTaskInfo(@RequestParam String processInstanceId) {
        String errorMessage;
        List<FlowTaskComment> taskCommentList =
                flowTaskCommentService.getFlowTaskCommentList(processInstanceId);
        if (CollUtil.isEmpty(taskCommentList)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        FlowTaskComment taskComment = taskCommentList.get(0);
        if (ObjectUtil.notEqual(taskComment.getCreateUserId(), SecureUtil.getUserId())) {
            errorMessage = "数据验证失败，当前流程发起人与当前用户不匹配！";
            return R.fail(errorMessage);
        }
        HistoricTaskInstance task = flowApiService.getHistoricTaskInstance(processInstanceId, taskComment.getTaskId());
        if (StrUtil.isBlank(task.getFormKey())) {
            errorMessage = "数据验证失败，指定任务的formKey属性不存在，请重新修改流程图！";
			return R.fail(errorMessage);
        }
        TaskInfoVo taskInfo = JSON.parseObject(task.getFormKey(), TaskInfoVo.class);
		// 用formid获取表单呈现方式
		if(taskInfo != null && null != taskInfo.getFormId()) {
			OnlineForm onlineForm = onlineFormService.getById(taskInfo.getFormId());
			taskInfo.setPresentMode(onlineForm.getPresentMode());
		}

        taskInfo.setTaskKey(task.getTaskDefinitionKey());
        return R.data(taskInfo);
    }

    /**
     * 提交多实例加签。
     *
     * @param processInstanceId 流程实例Id。
     * @param taskId            多实例任务的上一级任务Id。
     * @param newAssignees      新的加签人列表，多个指派人之间逗号分隔。
     * @return 应答结果。
     */
    @PostMapping("/submitConsign")
	@ApiOperation(notes = "提交多实例加签",value = "提交多实例加签")
	public R<Void> submitConsign(
            @RequestBody(required = true) String processInstanceId,
            @RequestBody(required = true) String taskId,
            @RequestBody(required = true) String newAssignees) {
        String errorMessage;
        if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
            errorMessage = "数据验证失败，当前流程实例已经结束，不能执行加签！";
            return R.fail(errorMessage);
        }
        HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
        if (taskInstance == null) {
            errorMessage = "数据验证失败，当前任务不存在！";
			return R.fail(errorMessage);
        }
        if (!StrUtil.equals(taskInstance.getAssignee(), SecureUtil.getUserAccount())) {
            errorMessage = "数据验证失败，任务指派人与当前用户不匹配！";
			return R.fail(errorMessage);
        }
        List<Task> activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId);
        Task activeMultiInstanceTask = null;
        for (Task activeTask : activeTaskList) {
            Object startTaskId = flowApiService.getTaskVariable(
                    activeTask.getId(), FlowConstant.MULTI_SIGN_START_TASK_VAR);
            if (startTaskId != null && startTaskId.toString().equals(taskId)) {
                activeMultiInstanceTask = activeTask;
                break;
            }
        }
        if (activeMultiInstanceTask == null) {
            errorMessage = "数据验证失败，指定加签任务不存在或已审批完毕！";
			return R.fail(errorMessage);
        }
        flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees);
        return R.success("加签成功");
    }

    /**
     * 返回当前用户待办的任务列表。
     *
     * @param processDefinitionKey  流程标识。
     * @param processDefinitionName 流程定义名 (模糊查询)。
     * @param taskName              任务名称 (魔术查询。
     * @return 返回当前用户待办的任务列表。如果指定流程标识，则仅返回该流程的待办任务列表。
     */
	@PostMapping("/listRuntimeTask")
	@ApiOperation(notes = "返回当前用户待办的任务列表",value = "返回当前用户待办的任务列表")
	public R<IPage<FlowTaskVo>> listRuntimeTask(@RequestParam(required = false) String processDefinitionKey,
												@RequestParam(required = false) String processDefinitionName,
												@RequestParam(required = false) String taskName,
												@RequestParam(required = false,value = "pageParam") String  pageParam) throws ParseException {
		try {
			MyPageParam query = JSON.parseObject(pageParam, MyPageParam.class);
			IPage<Task> page = new Page<>(query.getPageNum(), query.getPageSize());
			IPage<Task> pageData = flowApiService.getTaskListByUserName(
				SecureUtil.getUserAccount(), processDefinitionKey, processDefinitionName, taskName, page);
			List<FlowTaskVo> flowTaskVoList = flowApiService.convertToFlowTaskList(pageData.getRecords());
			IPage<FlowTaskVo> flowTaskIPage = new Page<>(query.getPageNum(), query.getPageSize());
			flowTaskIPage.setRecords(flowTaskVoList);
			flowTaskIPage.setTotal(pageData.getTotal());
			return R.data(flowTaskIPage);
		}catch (Exception e){
			e.printStackTrace();
		}
		return R.status(Boolean.FALSE);
	}

    /**
     * 返回当前用户待办的任务数量。
     *
     * @return 返回当前用户待办的任务数量。
     */
    @PostMapping("/countRuntimeTask")
	@ApiOperation(notes = "返回当前用户待办的任务数量",value = "返回当前用户待办的任务数量")
	public R<Long> countRuntimeTask() {
        long totalCount = flowApiService.getTaskCountByUserName(SecureUtil.getUserAccount());
        return R.data(totalCount);
    }

    /**
     * 获取当前流程任务的审批列表。
     *
     * @param processInstanceId 当前运行时的流程实例Id。
     * @return 当前流程实例的详情数据。
     */
    @GetMapping("/listFlowTaskComment")
	@ApiOperation(notes = "获取当前流程任务的审批列表",value = "获取当前流程任务的审批列表")
	public R<List<FlowTaskCommentVo>> listFlowTaskComment(@RequestParam String processInstanceId) {
        List<FlowTaskComment> flowTaskCommentList = flowTaskCommentService.getFlowTaskCommentList(processInstanceId);
        return R.data(FlowOperationWrapper.build().listVO(flowTaskCommentList));
    }

    /**
     * 获取指定流程定义的流程图。
     *
     * @param processDefinitionId 流程定义Id。
     * @return 流程图。
     */
    @GetMapping("/viewProcessBpmn")
	@ApiOperation(notes = "获取指定流程定义的流程图",value = "获取指定流程定义的流程图")
	public R<String> viewProcessBpmn(@RequestParam String processDefinitionId) throws IOException {
        BpmnXMLConverter converter = new BpmnXMLConverter();
        BpmnModel bpmnModel = flowApiService.getBpmnModelByDefinitionId(processDefinitionId);
        byte[] xmlBytes = converter.convertToXML(bpmnModel);
        InputStream in = new ByteArrayInputStream(xmlBytes);
        return R.data(StreamUtils.copyToString(in, StandardCharsets.UTF_8));
    }

    /**
     * 获取流程图高亮数据。
     *
     * @param processInstanceId 流程实例Id。
     * @return 流程图高亮数据。
     */
    @GetMapping("/viewHighlightFlowData")
	@ApiOperation(notes = "获取流程图高亮数据",value = "获取流程图高亮数据")
	public R<JSONObject> viewHighlightFlowData(@RequestParam String processInstanceId) {
        HistoricProcessInstance hpi = flowApiService.getHistoricProcessInstance(processInstanceId);
        BpmnModel bpmnModel = flowApiService.getBpmnModelByDefinitionId(hpi.getProcessDefinitionId());
        List<Process> processList = bpmnModel.getProcesses();
        List<FlowElement> flowElementList = new LinkedList<>();
        processList.forEach(p -> flowElementList.addAll(p.getFlowElements()));
        Map<String, String> allSequenceFlowMap = new HashMap<>(16);
        for (FlowElement flowElement : flowElementList) {
            if (flowElement instanceof SequenceFlow) {
                SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                String ref = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                allSequenceFlowMap.put(ref + targetRef, sequenceFlow.getId());
            }
        }
        Set<String> finishedTaskSet = new LinkedHashSet<>();
        //获取流程实例的历史节点(全部执行过的节点，被拒绝的任务节点将会出现多次)
        List<HistoricActivityInstance> activityInstanceList =
                flowApiService.getHistoricActivityInstanceList(processInstanceId);
        Set<String> finishedTaskSequenceSet = new LinkedHashSet<>();
        for (int i = 0; i < activityInstanceList.size(); i++) {
            HistoricActivityInstance current = activityInstanceList.get(i);
            if (i != activityInstanceList.size() - 1) {
                HistoricActivityInstance next = activityInstanceList.get(i + 1);
                finishedTaskSequenceSet.add(current.getActivityId() + next.getActivityId());
            }
            finishedTaskSet.add(current.getActivityId());
        }
        Set<String> finishedSequenceFlowSet = new HashSet<>();
        finishedTaskSequenceSet.forEach(s -> finishedSequenceFlowSet.add(allSequenceFlowMap.get(s)));
        //获取流程实例当前正在待办的节点
        List<HistoricActivityInstance> unfinishedInstanceList =
                flowApiService.getHistoricUnfinishedInstanceList(processInstanceId);
        Set<String> unfinishedTaskSet = new LinkedHashSet<>();
        for (HistoricActivityInstance unfinishedActivity : unfinishedInstanceList) {
            unfinishedTaskSet.add(unfinishedActivity.getActivityId());
        }
        JSONObject jsonData = new JSONObject();
        jsonData.put("finishedTaskSet", finishedTaskSet);
        jsonData.put("finishedSequenceFlowSet", finishedSequenceFlowSet);
        jsonData.put("unfinishedTaskSet", unfinishedTaskSet);
        return R.data(jsonData);
    }

    /**
     * 获取当前用户的已办理的审批任务列表。
     *
     * @param processDefinitionName 流程名。
     * @param beginDate             流程发起开始时间。
     * @param endDate               流程发起结束时间。
     * @return 查询结果应答。
     */
    @PostMapping("/listHistoricTask")
	@ApiOperation(notes = "获取当前用户的已办理的审批任务列表",value = "获取当前用户的已办理的审批任务列表")
	public R<IPage<Map<String, Object>>> listHistoricTask(
		@RequestParam(required = false) String processDefinitionName,
		@RequestParam(required = false) String beginDate,
		@RequestParam(required = false) String endDate,
		@RequestParam(required = false,value = "pageParam") String  pageParam) throws ParseException {
        MyPageParam query = JSON.parseObject(pageParam,MyPageParam.class);
    	IPage<HistoricTaskInstance> page = new Page<>(query.getPageNum(), query.getPageSize());

		IPage<HistoricTaskInstance> pageData =
			flowApiService.getHistoricTaskInstanceFinishedList(processDefinitionName, beginDate, endDate, page);
		List<Map<String, Object>> resultList = new LinkedList<>();
		pageData.getRecords().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance)));
		List<HistoricTaskInstance> taskInstanceList = pageData.getRecords();
		if (CollUtil.isNotEmpty(taskInstanceList)) {
			Set<String> instanceIdSet = taskInstanceList.stream()
				.map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toSet());
			List<HistoricProcessInstance> instanceList = flowApiService.getHistoricProcessInstanceList(instanceIdSet);
			Map<String, HistoricProcessInstance> instanceMap =
				instanceList.stream().collect(Collectors.toMap(HistoricProcessInstance::getId, c -> c));
			resultList.forEach(result -> {
				HistoricProcessInstance instance = instanceMap.get(result.get("processInstanceId").toString());
				result.put("processDefinitionKey", instance.getProcessDefinitionKey());
				result.put("processDefinitionName", instance.getProcessDefinitionName());
				result.put("startUser", instance.getStartUserId());
				result.put("businessKey", instance.getBusinessKey());
			});
			Set<String> taskIdSet =
				taskInstanceList.stream().map(HistoricTaskInstance::getId).collect(Collectors.toSet());
			List<FlowTaskComment> commentList = flowTaskCommentService.getFlowTaskCommentListByTaskIds(taskIdSet);
			Map<String, List<FlowTaskComment>> commentMap =
				commentList.stream().collect(Collectors.groupingBy(FlowTaskComment::getTaskId));
			resultList.forEach(result -> {
				List<FlowTaskComment> comments = commentMap.get(result.get("id").toString());
				if (CollUtil.isNotEmpty(comments)) {
					result.put("approvalType", comments.get(0).getApprovalType());
					comments.remove(0);
				}
			});
		}

		IPage<Map<String, Object>> rtnPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
		rtnPage.setRecords(resultList);
		return R.data(rtnPage);
	}

    /**
     * 根据输入参数查询，当前用户的历史流程数据。
     *
     * @param processDefinitionName 流程名。
     * @param beginDate             流程发起开始时间。
     * @param endDate               流程发起结束时间。
     * @return 查询结果应答。
     */
    @PostMapping("/listHistoricProcessInstance")
	@ApiOperation(notes = "根据输入参数查询，当前用户的历史流程数据",value = "根据输入参数查询，当前用户的历史流程数据")
	public R<IPage<Map<String, Object>>> listHistoricProcessInstance(
            @RequestParam(required = false) String processDefinitionName,
            @RequestParam(required = false) String beginDate,
            @RequestParam(required = false) String endDate,
			@RequestParam(required = false,value = "pageParam") String  pageParam) throws ParseException {
		MyPageParam query = JSON.parseObject(pageParam,MyPageParam.class);

		IPage<HistoricProcessInstance> page = new Page<>(query.getPageNum(), query.getPageSize());
		IPage<HistoricProcessInstance> pageData = flowApiService.getHistoricProcessInstanceList(
                null, processDefinitionName, SecureUtil.getUserAccount(), beginDate, endDate, page, true);
        List<Map<String, Object>> resultList = new LinkedList<>();
        pageData.getRecords().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance)));

		IPage<Map<String, Object>> rtnPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
		rtnPage.setRecords(resultList);
		return R.data(rtnPage);
    }

    /**
     * 根据输入参数查询，所有历史流程数据。
     *
     * @param processDefinitionName 流程名。
     * @param startUser             流程发起用户。
     * @param beginDate             流程发起开始时间。
     * @param endDate               流程发起结束时间。
     * @return 查询结果。
     */
    @PostMapping("/listAllHistoricProcessInstance")
	@ApiOperation(notes = "根据输入参数查询，所有历史流程数据",value = "根据输入参数查询，所有历史流程数据")
	public R<IPage<Map<String, Object>>> listAllHistoricProcessInstance(
            @RequestParam(required = false) String processDefinitionName,
            @RequestParam(required = false) String startUser,
            @RequestParam(required = false) String beginDate,
            @RequestParam(required = false) String endDate,
			@RequestParam(required = false,value = "pageParam") String  pageParam) throws ParseException {
		MyPageParam query = JSON.parseObject(pageParam,MyPageParam.class);
		IPage<HistoricProcessInstance> page = new Page<>(query.getPageNum(), query.getPageSize());
		IPage<HistoricProcessInstance> pageData = flowApiService.getHistoricProcessInstanceList(
                null, processDefinitionName, startUser, beginDate, endDate, page, false);
        List<Map<String, Object>> resultList = new LinkedList<>();
        pageData.getRecords().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance)));

		IPage<Map<String, Object>> rtnPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
		rtnPage.setRecords(resultList);
		return R.data(rtnPage);
    }

    /**
     * 催办工单，只有流程发起人才可以催办工单。
     * 催办场景必须要取消数据权限过滤，因为流程的指派很可能是跨越部门的。
     * 既然被指派和催办了，这里就应该禁用工单表的数据权限过滤约束。
     * 如果您的系统没有支持数据权限过滤，DisableDataFilter不会有任何影响，建议保留。
     *
     * @param workOrderId 工单Id。
     * @return 应答结果。
     */
    @DisableDataFilter
    @PostMapping("/remindRuntimeTask")
	@ApiOperation(notes = "催办工单",value = "催办工单")
	public R<Void> remindRuntimeTask(@RequestBody(required = true) Long workOrderId) {
        FlowWorkOrder flowWorkOrder = flowWorkOrderService.getById(workOrderId);
        if (flowWorkOrder == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        String errorMessage;
        if (!flowWorkOrder.getCreateUserId().equals(SecureUtil.getUserId())) {
            errorMessage = "数据验证失败，只有流程发起人才能催办工单!";
            return R.fail(errorMessage);
        }
        if (flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.FINISHED)) {
            errorMessage = "数据验证失败，已经结束的流程，不能催办工单！";
			return R.fail(errorMessage);
        }

		List<Task> taskList =
			flowApiService.getProcessInstanceActiveTaskList(flowWorkOrder.getProcessInstanceId());
        flowMessageService.saveNewRemindMessage(taskList, flowWorkOrder);
        return R.success("催办成功");
    }

    /**
     * 取消工作流工单，仅当没有进入任何审批流程之前，才可以取消工单。
     *
     * @param workOrderId  工单Id。
     * @param cancelReason 取消原因。
     * @return 应答结果。
     */
    @DisableDataFilter
    @PostMapping("/cancelWorkOrder")
    public R<Void> cancelWorkOrder(
            @RequestBody(required = true) Long workOrderId,
            @RequestBody(required = true) String cancelReason) {
        FlowWorkOrder flowWorkOrder = flowWorkOrderService.getById(workOrderId);
        if (flowWorkOrder == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        String errorMessage;
        if (!flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.SUBMITTED)) {
            errorMessage = "数据验证失败，当前流程已经进入审批状态，不能撤销工单！";
            return R.fail(errorMessage);
        }
        if (!flowWorkOrder.getCreateUserId().equals(SecureUtil.getUserId())) {
            errorMessage = "数据验证失败，当前用户不是工单所有者，不能撤销工单！";
			return R.fail(errorMessage);
        }
        R result = flowApiService.stopProcessInstance(
                flowWorkOrder.getProcessInstanceId(), cancelReason, true);
        if (!result.isSuccess()) {
            return R.fail(result.getMsg());
        }
        return R.success("工单取消成功");
    }

    /**
     * 终止流程实例，将任务从当前节点直接流转到主流程的结束事件。
     *
     * @param processInstanceId 流程实例Id。
     * @param stopReason        停止原因。
     * @return 执行结果应答。
     */
    @DisableDataFilter
    @PostMapping("/stopProcessInstance")
    public R<Void> stopProcessInstance(
            @RequestBody(required = true) String processInstanceId,
            @RequestBody(required = true) String stopReason) {
        R result = flowApiService.stopProcessInstance(processInstanceId, stopReason, false);
        if (!result.isSuccess()) {
            return R.fail(result.getMsg());
        }
        return R.success("终止流程实例成功");
    }

    /**
     * 删除流程实例。
     *
     * @param processInstanceId 流程实例Id。
     * @return 执行结果应答。
     */
    @PostMapping("/deleteProcessInstance")
    public R<Void> deleteProcessInstance(@RequestBody(required = true) String processInstanceId) {
        flowApiService.deleteProcessInstance(processInstanceId);
        return R.success("删除流程实例成功");
    }
}
